/*
 * $Id: SignUpController.java 46 2013-05-03 21:38:12Z gabakyan $
 * $Author: gabakyan $
 * $Revision: 46 $
 * $Date: 2013-05-03 21:38:12 +0000 (Fri, 03 May 2013) $
 *
 * Copyright (c) 2013 Supply Chain Intelligence (SCI), Inc.
 * http://www.scintelligence.com/, Email: info@scintelligence.com
 * All rights reserved.
 *
 * This file is part of Logistics Map.
 *
 * Logistics Map is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, version 3 of the License.
 *
 * Logistics Map is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Logistics Map.  If not, see <http://www.gnu.org/licenses/>.
 */

package com.sci.logisticsmap.web.controller;

import com.sci.logisticsmap.service.UserService;
import com.sci.logisticsmap.support.model.UserStatus;
import com.sci.logisticsmap.support.model.UserType;
import com.sci.logisticsmap.support.Utilities;
import com.sci.logisticsmap.service.model.SignInDTCommand;
import com.sci.logisticsmap.service.model.SignUpContinueDTCommand;
import com.sci.logisticsmap.service.model.SessionUserDTModel;
import com.sci.logisticsmap.service.model.SignUpDTCommand;
import com.sci.logisticsmap.web.security.support.SecurityContextHelper;
import com.sci.logisticsmap.web.model.SignInVWCommand;
import com.sci.logisticsmap.web.model.SignUpContinueVWCommand;
import com.sci.logisticsmap.web.model.SignUpVWCommand;
import com.sci.logisticsmap.support.validator.CompoundValidator;
import com.sci.logisticsmap.web.support.validator.SignInVWCommandValidator;
import com.sci.logisticsmap.web.support.validator.SignUpContinueVWCommandValidator;
import com.sci.logisticsmap.web.support.validator.SignUpVWCommandValidator;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.*;

import javax.annotation.PostConstruct;
import javax.validation.Valid;

/**
 * The Controller for processing sign up view/ajax requests.
 *
 * @author gabakyan@gmail.com (Last modified by $Author: gabakyan $)
 * @version $Revision: 46 $
 */
@Controller
@RequestMapping("")
public class SignUpController extends BaseController {
    /**
     * The sign up path.
     */
    public static final String PATH_SIGN_UP = "/sign-up";
    /**
     * The sign up confirmation path.
     */
    public static final String PATH_SIGN_UP_CONFIRMATION = "/sign-up-confirmation";
    /**
     * The sign up confirmation success path.
     */
    public static final String PATH_SIGN_UP_CONFIRMATION_SUCCESS = "/sign-up-confirmation-success";
    /**
     * The sign up confirmation success final path.
     */
    public static final String PATH_SIGN_UP_CONFIRMATION_SUCCESS_FINAL = "/sign-up-confirmation-success-final";
    /**
     * The sign up continue path.
     */
    public static final String PATH_SIGN_UP_CONTINUE = "/sign-up-continue";
    /**
     * The sign up success path.
     */
    public static final String PATH_SIGN_UP_SUCCESS = "/sign-up-success";
    /**
     * The sign up success final path.
     */
    public static final String PATH_SIGN_UP_SUCCESS_FINAL = "/sign-up-success-final";

    /**
     * The sign up view.
     */
    private static final String viewSignUp = "signUpPage";
    /**
     * The sign up confirmation view.
     */
    private static final String viewSignUpConfirmation = "signUpConfirmationPage";
    /**
     * The sign up confirmation success view.
     */
    private static final String viewSignUpConfirmationSuccess = "signUpConfirmationSuccessPage";
    /**
     * The sign up confirmation success final view.
     */
    private static final String viewSignUpConfirmationSuccessFinal = "signUpConfirmationSuccessFinalPage";
    /**
     * The sign up continue view.
     */
    private static final String viewSignUpContinue = "signUpContinuePage";
    /**
     * The sign up success view.
     */
    private static final String viewSignUpSuccess = "signUpSuccessPage";
    /**
     * The sign up success final view.
     */
    private static final String viewSignUpSuccessFinal = "signUpSuccessFinalPage";

    /**
     * The user service.
     */
    @Autowired
    private UserService userService;

    /**
     * The default constructor.
     * Initializes a Controller class.
     */
    public SignUpController() {
    }

    /*
     * (non-Javadoc)
     *
     * @see BaseController#init()
     */
    @PostConstruct
    public void init() {
        super.init();
    }

    /*
     * (non-Javadoc)
     *
     * @see org.springframework.web.bind.annotation.InitBinder
     */
    @InitBinder
    protected void initBinder(WebDataBinder binder) {
        binder.setValidator(new CompoundValidator(new SignInVWCommandValidator(),
                new SignUpVWCommandValidator(), new SignUpContinueVWCommandValidator()));
    }

    /**
     * The method to response on the sign up view request.
     *
     * @param  model
     *         The model.
     *
     * @return the sign up view.
     */
    @RequestMapping(value=PATH_SIGN_UP, method={RequestMethod.GET})
    public String onSignUp(Model model) {
        try {
            SignUpDTCommand signUpCommand = new SignUpDTCommand();
            model.addAttribute("signUpCommand", conversionUtilities.convert(signUpCommand, SignUpVWCommand.class));
        } catch (Exception e) {
            addExceptionToModel(model, e);
        }

        return viewSignUp;
    }

    /**
     * The method to response on the sign up view request.
     *
     * @param  command
     *         The command.
     * @param  result
     *         The validation binding result.
     * @param  model
     *         The model.
     *
     * @return the sign up view.
     */
    @RequestMapping(value=PATH_SIGN_UP, method={RequestMethod.POST})
    public String onSignUpSubmit(@ModelAttribute("signUpCommand") @Valid SignUpVWCommand command, BindingResult result, Model model) {
        try {
            boolean failed = false;
            if (!result.hasErrors()) {
                try {
                    /*SessionUserDTModel sessionUser = */userService.signUp(conversionUtilities.convert(command, SignUpDTCommand.class));
                    return buildRedirectToPath(PATH_SIGN_UP_CONTINUE);
                } catch (Exception e) {
                    addExceptionToModel(model, e);
                    failed = true;
                }
            } else {
                failed = true;
            }
        } catch (Exception e) {
            addExceptionToModel(model, e);
        }

        return viewSignUp;
    }

    /**
     * The method to response on the sign up confirmation view request.
     *
     * @param  email
     *         The email.
     * @param  confirmationCode
     *         The confirmation code.
     * @param  model
     *         The model.
     *
     * @return the sign up confirmation view.
     */
    @RequestMapping(value=PATH_SIGN_UP_CONFIRMATION, method={RequestMethod.GET})
    public String onSignUpConfirmation(@RequestParam(value="email", required=false) String email,
                                       @RequestParam(value="code", required=false) String confirmationCode,
                                       Model model) {
        try {
            String messageKey;
            if (StringUtils.isNotBlank(email) && StringUtils.isNotBlank(confirmationCode)) {
                logger.debug("email = {}, confirmationCode = {}", email, confirmationCode);

                SessionUserDTModel sessionUser = SecurityContextHelper.getAuthenticatedUserDTModel();
                if (sessionUser == null || sessionUser.getUsername().equals(email)) {
                    if (userService.signUpConfirmation(sessionUser, email, confirmationCode)) {
                        logger.debug("confirmation passed");

                        if (sessionUser == null) {
                            return buildRedirectToPath(PATH_SIGN_UP_CONFIRMATION_SUCCESS,
                                    Utilities.buildString("?email=", Utilities.encodeURLParameter(email)));
                        } else {
                            return buildRedirectToPath(PATH_SIGN_UP_CONFIRMATION_SUCCESS_FINAL);
                        }
                    } else {
                        messageKey = "pages.signUpConfirmationPage.messages.wrongEmailOrConfirmationCode";
                    }
                } else {
                    messageKey = "pages.signUpConfirmationPage.messages.wrongEmailOrConfirmationCode";
                }
            } else {
                messageKey = "pages.signUpConfirmationPage.messages.emptyEmailOrConfirmationCode";
            }

            addCustomMessageKeyToModel(model, "confirmationMessageKey", messageKey);
        } catch (Exception e) {
            addExceptionToModel(model, e);
        }

        return viewSignUpConfirmation;
    }

    /**
     * The method to response on the sign up confirmation success view request.
     *
     * @param  email
     *         The email.
     * @param  model
     *         The model.
     *
     * @return the sign up confirmation success view.
     */
    @RequestMapping(value=PATH_SIGN_UP_CONFIRMATION_SUCCESS, method={RequestMethod.GET})
    public String onSignUpConfirmationSuccess(@RequestParam(value="email", required=false) String email, Model model) {
        try {
            SignInDTCommand signInCommand = new SignInDTCommand();
            if (StringUtils.isNotBlank(email)) {
                signInCommand.setUsername(email);
            }
            model.addAttribute("signInCommand", conversionUtilities.convert(signInCommand, SignInVWCommand.class));
        } catch (Exception e) {
            addExceptionToModel(model, e);
        }

        return viewSignUpConfirmationSuccess;
    }

    /**
     * The method to response on the sign up confirmation success final view request.
     *
     * @param  model
     *         The model.
     *
     * @return the sign up confirmation success final view.
     */
    @RequestMapping(value=PATH_SIGN_UP_CONFIRMATION_SUCCESS_FINAL, method={RequestMethod.GET})
    public String onSignUpConfirmationSuccessFinal(Model model) {
        return viewSignUpConfirmationSuccessFinal;
    }

    /**
     * The method to response on the sign up continue view request.
     *
     * @param  model
     *         The model.
     *
     * @return the sign up continue view.
     */
    @RequestMapping(value=PATH_SIGN_UP_CONTINUE, method={RequestMethod.GET})
    public String onSignUpContinue(Model model) {
        try {
            SignUpContinueDTCommand signUpContinueCommand = new SignUpContinueDTCommand();
            model.addAttribute("signUpContinueCommand", conversionUtilities.convert(signUpContinueCommand, SignUpContinueVWCommand.class));
        } catch (Exception e) {
            addExceptionToModel(model, e);
        }

        return viewSignUpContinue;
    }

    /**
     * The method to response on the sign up continue view submitting request.
     *
     * @param  command
     *         The command.
     * @param  result
     *         The validation binding result.
     * @param  model
     *         The model.
     *
     * @return the sign up continue view.
     */
    @RequestMapping(value=PATH_SIGN_UP_CONTINUE, method={RequestMethod.POST})
    public String onSignUpContinueSubmit(@ModelAttribute("signUpContinueCommand") @Valid SignUpContinueVWCommand command, BindingResult result, Model model) {
        try {
            boolean failed = false;
            if (!result.hasErrors()) {
                try {
                    SessionUserDTModel sessionUser = SecurityContextHelper.getAuthenticatedUserDTModel();

                    userService.signUpContinue(sessionUser, conversionUtilities.convert(command, SignUpContinueDTCommand.class));

                    if (sessionUser.getType() != null) {
                        if (sessionUser.getType().equals(UserType.OPENID_USER)) {
                            return buildRedirectToPath(PATH_SIGN_UP_SUCCESS_FINAL);
                        } else {
                            if (sessionUser.getStatus() != null) {
                                if (sessionUser.getStatus().equals(UserStatus.NEW)) {
                                    return buildRedirectToPath(PATH_SIGN_UP_SUCCESS);
                                } else {
                                    return buildRedirectToPath(PATH_SIGN_UP_SUCCESS_FINAL);
                                }
                            }
                        }
                    }
                } catch (Exception e) {
                    addExceptionToModel(model, e);
                    failed = true;
                }
            } else {
                failed = true;
            }
        } catch (Exception e) {
            addExceptionToModel(model, e);
        }

        return viewSignUpContinue;
    }

    /**
     * The method to response on the sign up success view request.
     *
     * @param  model
     *         The model.
     *
     * @return the sign up success view.
     */
    @RequestMapping(value=PATH_SIGN_UP_SUCCESS, method={RequestMethod.GET})
    public String onSignUpSuccess(Model model) {
        return viewSignUpSuccess;
    }

    /**
     * The method to response on the sign up success final view request.
     *
     * @param  model
     *         The model.
     *
     * @return the sign up success final view.
     */
    @RequestMapping(value=PATH_SIGN_UP_SUCCESS_FINAL, method={RequestMethod.GET})
    public String onSignUpSuccessFinal(Model model) {
        return viewSignUpSuccessFinal;
    }
}
